//taitan公司自定义的Sld 样式
//sld与mvt样式区别：sld针对一个要素多个rule的样式可以同时独立生效，而mvt只能给一个要素设置一个样式 

(function (window) {

    function TaitanPbfStyle(options) {
        this.ol = null;
        this.json = {};
        this.options = {};
        this.style = {};
        this.iconCache = {};
        this.properties = null;
        this.type = null;
        this.scale = null;
        this.resolution = null;
        this.filterIsPass = null;
        this.scaleIsPass = true;
        this.init(options);
    }

    TaitanPbfStyle.prototype = {
        constructor: TaitanPbfStyle,

        defaults: {
            ol: null,
            json: {}
        },

        init: function (options) {
            let opts = Object.assign({}, this.defaults, options);
            this.json = opts.json;
            this.ol = opts.ol;
        },

        reset: function () {
            this.options = {};
            this.style = {};
            this.properties = null;
            this.type = null;
            this.scale = null;
            this.resolution = null;
            this.filterIsPass = null;
            this.scaleIsPass = true;
        },

        getStyle: function () {
            let This = this;
            return function (feature, resolution) {
                This.reset();
                This.type = feature.getGeometry().getType();
                This.properties = feature.getProperties();
                This.resolution = resolution;
                This.scale = 1 / (0.0254 / (96 * resolution));
                This.filter();
                return This.buildStyle();
            }
        },

        // 根据options组装最终的样式对象
        buildStyle: function () {
            if (Object.keys(this.options).length == 0) return [new this.ol.style.Style({})];
            // if (JSON.stringify(this.options) == '{}') return;

            // 组装基础样式
            switch (this.type.toLowerCase()) {
                case 'point':
                    if (this.options.image.imageStyle) this.style.image = this.options.image.imageStyle;
                    break;

                case 'linestring':
                    if (this.options.stroke) this.style.stroke = this.options.stroke;
                    break;

                case 'polygon':
                    if (this.options.fill) this.style.fill = this.options.fill;
                    if (this.options.stroke) this.style.stroke = this.options.stroke;
                    break;

                default:
                    break;
            }

            // 组装label样式,这里控制了下显示层级，只有分辨率小于40的时候才会显示label，后续可以做成可配置项
            if (this.resolution < 40 && this.options.text) {
                this.style.text = new this.ol.style.Text({
                    text: this.options.text.text ? this.options.text.text + '' : '',
                    textBaseline: "top",
                    overflow: 'line',
                    font: `${this.options.text.font || 10}px sans-serif`,
                    offsetX: this.options.text.offsetX,
                    offsetY: this.options.text.offsetY,
                    fill: this.options.text.fill,
                    stroke: this.options.text.stroke,
                    rotateWithView: false
                })
            }

            // 组装层级样式
            this.style.zIndex = this.options.zIndex || 1;
            return [new this.ol.style.Style(this.style)];
        },

        // 构建样式options
        buildOptions: function (rule) {
            // rule.Symbolizer.WellKnownName = 'img';
            // rule.Symbolizer.src = 'https://unpkg.com/@mapbox/maki@4.0.0/icons/park-15.svg';

            this.options.image = {};
            this.options.image.rotation = rule.Symbolizer.Rotation || 0;

            if (rule.Symbolizer.FillColor && rule.Symbolizer.WellKnownName != 'img') {
                let imgFillColor = this.buildRgba(rule.Symbolizer.FillColor, rule.Symbolizer.FillOpacity);
                this.options.image.fill = new this.ol.style.Fill({
                    color: imgFillColor
                });

                if (rule.Symbolizer.StrokeColor) {
                    let imgStrokeColor = this.buildRgba(rule.Symbolizer.StrokeColor, rule.Symbolizer.StrokeOpacity);
                    this.options.image.stroke = new this.ol.style.Stroke({
                        color: imgStrokeColor,
                        width: rule.Symbolizer.StrokeWidth,
                        lineDash: rule.Symbolizer.StrokeDasharray.split(' ')
                    });
                }
            }

            this.options.image.render = "image";

            switch (rule.Symbolizer.WellKnownName) {
                case 'circle':
                    // 圆形
                    this.options.image.radius = rule.Symbolizer.Size;
                    this.options.image.imageStyle = new this.ol.style.Circle(this.options.image);
                    break;

                case 'square':
                    // 正方形
                    this.options.image.radius = rule.Symbolizer.Size;
                    this.options.image.points = 4;
                    this.options.image.angle = Math.PI / 4;
                    this.options.image.imageStyle = new this.ol.style.RegularShape(this.options.image);
                    break;

                case 'triangle':
                    // 三角形
                    this.options.image.radius = rule.Symbolizer.Size;
                    this.options.image.points = 3;
                    this.options.image.angle = 0;
                    this.options.image.imageStyle = new this.ol.style.RegularShape(this.options.image);
                    break;

                case 'star':
                    // 五角形
                    this.options.image.radius = rule.Symbolizer.Size;
                    this.options.image.points = 5;
                    this.options.image.radius2 = rule.Symbolizer.Size / 2.5;
                    this.options.image.angle = 0;
                    this.options.image.imageStyle = new this.ol.style.RegularShape(this.options.image);
                    break;

                case 'cross':
                    // 十字架
                    this.options.image.radius = rule.Symbolizer.Size;
                    this.options.image.points = 4;
                    this.options.image.radius2 = 0;
                    this.options.image.angle = 0;
                    this.options.image.imageStyle = new this.ol.style.RegularShape(this.options.image);
                    break;

                case 'x':
                    // ×形
                    this.options.image.radius = rule.Symbolizer.Size;
                    this.options.image.points = 4;
                    this.options.image.radius2 = 0;
                    this.options.image.angle = Math.PI / 4;
                    this.options.image.imageStyle = new this.ol.style.RegularShape(this.options.image);
                    break;

                case 'img':
                    let icon = this.iconCache[rule.Symbolizer.src];
                    if (!icon) {
                        this.options.image.src = rule.Symbolizer.src;
                        this.options.image.anchorXUnits = 'fraction';
                        this.options.image.anchorYUnits = 'fraction';
                        this.options.image.anchor = [0.5, 0.5];
                        this.options.image.offset = [0, 0];
                        this.options.image.scale = 1;
                        this.options.image.rotation = rule.Symbolizer.Rotation;
                        this.options.image.crossOrigin = 'anonymous',
                            this.options.image.imageStyle = new this.ol.style.Icon(this.options.image);
                        this.iconCache[rule.Symbolizer.src] = this.options.image.imageStyle;
                    } else {
                        this.options.image.imageStyle = icon;
                    }
                    break;

                default:
                    break;
            }

            // 构建option中的填充色
            if (rule.Symbolizer.FillColor) {
                let fillColor = this.buildRgba(rule.Symbolizer.FillColor, rule.Symbolizer.FillOpacity);
                this.options.fill = new this.ol.style.Fill({
                    color: fillColor
                });
            }

            // 构建option中的边框
            let strokeColor, strokeWidth, strokeDasharray;
            if (rule.Symbolizer.StrokeColor) {
                strokeColor = this.buildRgba(rule.Symbolizer.StrokeColor, rule.Symbolizer.StrokeOpacity);

                if (rule.Symbolizer.StrokeWidth && rule.Symbolizer.StrokeWidth > 1) {
                    strokeWidth = rule.Symbolizer.StrokeWidth;
                }

                if (rule.Symbolizer.StrokeDasharray && rule.Symbolizer.StrokeDasharray.split(' ')) {
                    strokeDasharray = rule.Symbolizer.StrokeDasharray.split(' ');
                }

                this.options.stroke = new this.ol.style.Stroke({
                    color: strokeColor,
                    width: strokeWidth,
                    lineDash: strokeDasharray
                });
            }

            // 构建option中的标签
            if (rule.Label && JSON.stringify(rule.Label) != '{}') {
                this.options.text = {};
                this.options.text.text = this.properties[rule.Label.PropertyName];
                this.options.text.font = rule.Label.FontSize;
                this.options.text.offsetX = rule.Label.AnchorPointX;
                this.options.text.offsetY = rule.Label.AnchorPointY;

                if (rule.Label.FillColor) {
                    let fillColor = this.buildRgba(rule.Label.FillColor, rule.Label.FillOpacity);
                    this.options.text.fill = new this.ol.style.Fill({
                        color: fillColor
                    });
                }

                if (rule.Label.HaloFillColor) {
                    let haloFillColor = this.buildRgba(rule.Label.HaloFillColor, rule.Label.HaloFillOpacity);
                    this.options.text.stroke = new this.ol.style.Stroke({
                        color: haloFillColor,
                        width: rule.Label.HaloRadius
                    });
                }
            }
        },

        // 根据属性和比例条件进行判断
        filter: function () {
            for (let rule of this.json.Rule) {
                // 每次循环开始前将重置filterIsPass参数
                this.filterIsPass = undefined;

                // 判断属性过滤条件，如果属性过滤条件参数不存在或者为空，则不做进一步的判断，直接赋值true
                if (rule.Filter instanceof Object == false ||
                    JSON.stringify(rule.Filter) == '{}' ||
                    rule.Filter.Conditions == undefined ||
                    rule.Filter.Conditions.length == 0) {
                    this.filterIsPass = true;
                } else {
                    this.filterConditions(rule.Filter);
                }

                this.buildOptions(rule);

                // 判断比例条件是否符合
                // let minScale = rule.MinScaleDenominator ? rule.MinScaleDenominator : 10;
                // let maxScale = rule.MaxScaleDenominator ? rule.MaxScaleDenominator : 10000000000;
                // this.scaleIsPass = (this.scale < minScale || this.scale > maxScale) ? false : true;
                // if (this.filterIsPass && this.scaleIsPass) this.buildOptions(rule);
            }
        },

        // 根据属性过滤条件进行判断
        filterConditions: function (filter) {
            for (let condition of filter.Conditions) {
                let bool, val = this.properties[condition.PropertyName] + '' || '';
                switch (condition.Condition) {
                    case 'PropertyIsEqualTo':
                        bool = (val == condition.Literal);
                        break;

                    case 'PropertyIsNotEqualTo':
                        bool = (val != condition.Literal);
                        break;

                    case 'PropertyIsLike':
                        bool = (val.indexOf(condition.Literal) > -1);
                        break;

                    case 'PropertyIsBetween':
                        let num = parseFloat(val);
                        bool = (num >= condition.LowerBoundary.Literal) && (num <= condition.UpperBoundary.Literal);
                        break;

                    default:
                        break;
                }

                if (filter.FilterType == 'And') {
                    this.filterIsPass = (this.filterIsPass == undefined) ? bool : (this.filterIsPass && bool);
                } else if (filter.FilterType == 'Or') {
                    this.filterIsPass = (this.filterIsPass == undefined) ? bool : (this.filterIsPass || bool);
                }
            }
        },

        hexToRgb: function (hex) {
            let result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
            return result ? {
                r: parseInt(result[1], 16),
                g: parseInt(result[2], 16),
                b: parseInt(result[3], 16)
            } : null;
        },

        buildRgba: function (hex, opa) {
            hex = this.hexToRgb(hex);
            if (hex == 'null') return "";
            return `rgba(${hex.r},${hex.g},${hex.b},${opa})`;
        }
    }


    //对外接口 
    window.zz3d.TaitanPbfStyle = TaitanPbfStyle;


})(window);